package com.cgw.auth.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cgw.auth.constance.AuthConst;
import com.cgw.auth.entity.AuthorizeInfo;
import com.cgw.auth.entity.params.BackAuthQuery;
import com.cgw.auth.enumer.AuthRedisKey;
import com.cgw.auth.enumer.AuthStatus;
import com.cgw.auth.mapper.AuthorizeInfoMapper;
import com.cgw.auth.service.AuthorizeInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.gavin.core.constant.CommonConst;
import org.gavin.core.exception.DataException;
import org.gavin.core.exception.ParamException;
import org.gavin.core.utils.IdUtils;
import org.redis.service.RedisService;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author grl
 * @since 2024-04-26
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthorizeInfoServiceImpl extends ServiceImpl<AuthorizeInfoMapper, AuthorizeInfo> implements AuthorizeInfoService {

    private final RedisService redisService;

    @Override
    public Boolean saveAuth(AuthorizeInfo info) {
        checkParam(info);
        Long id = info.getId();
        LocalDateTime now = LocalDateTime.now();
        info.setUpdateTime(now);
        boolean flag;
        if (id != null) {
            // 新增
            info.setId(null);
            info.setCreateTime(now);
            // 生成AppKey;
            addAuthInfo(info);
            flag = save(info);
        } else {
            String appKey = info.getAppKey();
            info.setAppKey(null);
            info.setSecretKey(null);
            info.setCreateTime(null);
            flag = updateById(info);
            info.setAppKey(appKey);
        }
        // 同步Redis
        authorInfoToRedis(id);
        return flag;
    }

    @Override
    public AuthorizeInfo getAuthDetail(Long id) {
        return getById(id);
    }

    @Override
    public Page<AuthorizeInfo> getAuthList(BackAuthQuery query) {
        Page page = new Page<>(Objects.nonNull(query.getCurrentPage()) ? query.getCurrentPage() : 1,
                Objects.nonNull(query.getPageSize()) ? query.getCurrentPage() : 1);
        return baseMapper.getAuthList(page, query);
    }

    @Override
    public AuthorizeInfo getAuth(String appKey) {
        AuthRedisKey authAccessType = AuthRedisKey.AUTH_DETAILS;
        authAccessType.setKey(appKey);
        AuthorizeInfo authorizeInfo = redisService.get(authAccessType, AuthorizeInfo.class);
        if(authorizeInfo != null){
            return authorizeInfo;
        }
        LambdaQueryWrapper<AuthorizeInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AuthorizeInfo::getAppKey, appKey);
        List<AuthorizeInfo> authorizeInfos = baseMapper.selectList(wrapper);
        AuthorizeInfo auth = getAuthorizeInfo(authorizeInfos);
        authorInfoToRedis(auth);
        return auth;
    }

    /**
     * 设置授权信息
     *
     * @param info
     */
    private void addAuthInfo(AuthorizeInfo info) {
        String appKey = "DIS" + IdUtils.fastUUID().toUpperCase();
        String sk = DigestUtils.md5DigestAsHex(IdUtils.fastUUID().toUpperCase().getBytes(StandardCharsets.UTF_8));
        info.setAppKey(appKey);
        info.setSecretKey(sk);
    }


    private void checkParam(AuthorizeInfo info) {
        LambdaQueryWrapper<AuthorizeInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.ne(Objects.nonNull(info.getId()), AuthorizeInfo::getId, info.getId())
                .eq(AuthorizeInfo::getCompanyName, info.getCompanyName())
                .eq(AuthorizeInfo::getAppName, info.getAppName());
        if (exists(wrapper)) {
            throw ParamException.le(AuthStatus.APP_NAME_duplicates);
        }
    }

    private AuthorizeInfo getAuthorizeInfo(List<AuthorizeInfo> authorizeInfos) {
        AuthorizeInfo info = null;
        if (authorizeInfos.size() > CommonConst.ONE) {
            throw DataException.le(AuthStatus.FIND_MULTIPLE_DATA);
        }
        if (!authorizeInfos.isEmpty()) {
            info = authorizeInfos.get(0);
        }
        return info;
    }


    private void authorInfoToRedis(Long id){
        authorInfoToRedis(getAuthDetail(id));
    }

    private void authorInfoToRedis(AuthorizeInfo authDetail) {
        if(authDetail != null){
            AuthRedisKey detailsKey = AuthRedisKey.AUTH_DETAILS;
            detailsKey.set(authDetail.getAppKey(), JSON.toJSONString(authDetail));
            if(AuthConst.AUTH_STATUS_ENABLE.equals(authDetail.getStatus())){
                redisService.add(detailsKey);
            }else {
                redisService.deleteKey(detailsKey);
            }
        }
    }
}
